/**
 * Copyright (c) 2010 sonntagsfarben.de
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package de.sonntagsfarben.remoting.amf
{
	import flash.events.AsyncErrorEvent;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.NetStatusEvent;
	import flash.events.SecurityErrorEvent;
	import flash.utils.Proxy;
	import flash.utils.flash_proxy;

	dynamic public class RemoteService extends Proxy implements IEventDispatcher 
	{
		private var _gateway : String;
		private var _className : String;
		private var _connection : RemoteConnection;
		private var _dispatcher:EventDispatcher;
		private var _useMethodAsEventType : Boolean;
		

		//TODO Implementieren von flash_proxy!!!!

		public function RemoteService(gateway : String, className : String, useMethodAsEventType:Boolean = false)
		{
			_gateway = gateway;
			_className = className;
			_dispatcher = new EventDispatcher();
			this.useMethodAsEventType = useMethodAsEventType;
			registerAliases();
			_initConnection();
		}

		private function _initConnection() : void
		{
			_connection = new RemoteConnection();
			_connection.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus);
			_connection.addEventListener(IOErrorEvent.IO_ERROR, onConnectionError);
			_connection.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
			_connection.addEventListener(AsyncErrorEvent.ASYNC_ERROR, onAsyncError);
			_connection.connect(_gateway);
		}

		private function onAsyncError(event : AsyncErrorEvent) : void
		{
		}

		
		private function onConnectionError(event : IOErrorEvent) : void
		{
			dispatchEvent(event);
		}

		
		private function onNetStatus(e : NetStatusEvent) : void 
		{
			//trace("NetStatusEvent " + e.info["code"] + " " + e.info["level"]);
			if(String(e.info["level"]).toLowerCase() == "error") {
				//Logger.info(this, "Problems communicating with remote gateway!");
				dispatchEvent(new ServiceEvent(ServiceEvent.FAULT, null));
			}
			dispatchEvent(e);
		}
		
		
		
		private function onSecurityError(e : SecurityErrorEvent) : void 
		{
			dispatchEvent(e);
		}
		
		
		
		private function onResult(event : ServiceEvent) : void
		{
			if(_useMethodAsEventType) {
				var se : ServiceEvent = new ServiceEvent(event.method, event.result, event.method, event.service);
				dispatchEvent(se);
			} else {
				dispatchEvent(event);
			}
		}

		private function onFault(event : ServiceEvent) : void
		{
			dispatchEvent(event);
		}

		
		protected function registerAliases() : void
		{
		}

		
		public function call(methodName : String, responder : Responder = null, ...args) : void
		{
			if(responder == null)
				responder = defaultResponder;
		
			responder.service = _className;
			responder.method = methodName;
			responder.addEventListener(ServiceEvent.RESULT, onResult);
			responder.addEventListener(ServiceEvent.FAULT, onFault);
			
			var callParams : Array = [_className + "." + methodName];
			callParams.push(responder);
			callParams = callParams.concat(args);
			
			_connection.call.apply(null, callParams);
		}

		
		public function get defaultResponder() : Responder
		{
			return new Responder();
		}

		public function set defaultResponder(className : Responder) : void
		{
			// TODO: Implement me!!!
		}

		
		public final function set useMethodAsEventType(value : Boolean) : void
		{
			_useMethodAsEventType = value;
		}

		public final function get useMethodAsEventType() : Boolean
		{
			return _useMethodAsEventType;
		}

		
		public final function get name() : String
		{
			return this._className;
		}
		
		
		
		/*
		 *		 EventDispatcher;
		 */
		
		
		public function dispatchEvent(event : Event) : Boolean
		{
			return _dispatcher.dispatchEvent(event);
		}

		public function hasEventListener(type : String) : Boolean
		{
			return _dispatcher.hasEventListener(type);
		}

		public function willTrigger(type : String) : Boolean
		{
			return _dispatcher.willTrigger(type);
		}

		public function removeEventListener(type : String, listener : Function, useCapture : Boolean = false) : void
		{
			_dispatcher.removeEventListener(type, listener , useCapture );
		}

		public function addEventListener(type : String, listener : Function, useCapture : Boolean = false, priority : int = 0, useWeakReference : Boolean = false) : void
		{
			_dispatcher.addEventListener(type, listener, useCapture, priority, useWeakReference);		
		}
		
		
		//flash_proxy override function getProperty(name:*):* {
         //var cs:Namespace = _data.namespace("cs");
         //var qname:String = String(name);
        // return "Hans";//_data.cs::property.(@id == qname).@value;
      //}
		
		
		override flash_proxy function callProperty(methodName:*, ...args):*
		{
		//	Logger.debug(this, "callProperty "+methodName+" "+args);
			
			
			try {
		        var realArgs:Array = new Array().concat(args);
				realArgs.unshift(methodName);
		       	call(methodName , null , realArgs);
		        
		    }
		    catch (e:Error) {
		    	trace("callProperty Error:: "+e.message);
		    }

			
			
			
			
//			trace("callProperty: "+methodName,args);
//			service.addEventListener(methodName+"Result", redirectEvent);
//			service.addEventListener(methodName+"Fault", redirectEvent);
//			service.addEventListener(methodName+"Response", redirectEvent);
//			service.addEventListener(methodName+"Call", redirectEvent);
//			var realArgs:Array = new Array().concat(args);
//			realArgs.unshift(methodName);
//			service.callExternal.apply(service,realArgs);
			return null;
		}
		
		
		
		
		flash_proxy override function getProperty(name:*):* {
			
			//Logger.debug(this, "getProperty "+name);
			
//			trace("getProperty");
//			return 	function(...args):void
//					{
//						trace("llamada:",name,args,"service: "+service);
//						service.callExternal.apply(service,args);
//					};
			return "Hans";//null;
		}
		
		
		
		
	}
}